// NodePool.cpp: implementation of the CPGLObjectPtrPool class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <pgl/core/pgl.h>
#include <pgl/core/PGLObjectManager.h>
#include <pgl/core/PGLObjectPool.h>
#include <pgl/core/PGLObject.h>
#include <pgl/core/PGLBrush.h>
#include <pgl/core/PGLPools.h>
#include <pgl/core/PGLRegion.h>
#include <pgl/core/PGLArchive.h>
#include <pgl/core/PGLPools.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CPGLNode, CObject);

CPGLNode::CPGLNode()
:m_tID(0)
{
	m_tID=CPGLNodePoolSingleton::Instance()->InsertNode(
		boost::static_ptr<CPGLNode>(this)
		);
}

CPGLNode::CPGLNode(const CPGLNode& n)
:m_tID(0)
{
	m_tID=CPGLNodePoolSingleton::Instance()->InsertNode( 
		boost::static_ptr<CPGLNode>(this) 
		);
}

CPGLNode::~CPGLNode()
{
	CPGLNodePoolSingleton::Instance()->RemoveNode( m_tID );
}

void CPGLNode::SerializeXML( CPGLArchive& ar )
{
	static const TCHAR szTag[] = _T("CPGLNode");
	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());

	// loading own data
	if (ar.IsStoring())
	{
		xml.AddChildElemEx( _T("ID"), m_tID );
	}
	else
	{
		xml.FindGetChildData(_T("ID"), m_tID);
		CPGLNodePoolSingleton::Instance()->InsertNodeFixedID( 
			boost::static_ptr<CPGLNode>(this) 
			);
	}
}

CPGLNodePool::CPGLNodePool()
: m_uCurrentID(0)
{
	PGL_TRACE(_T("NodePool, starting\n"));
}

CPGLNodePool::~CPGLNodePool()
{
	PGL_TRACE(_T("NodePool, closing\n"));
#ifdef _DEBUG
	if (!m_mNodes.empty())
	{
		NodeContainer::iterator it;
		for (it = m_mNodes.begin(); it != m_mNodes.end(); ++it)
		{
			PGL_TRACE1(_T("\tClass: %d\n"), it->second->GetID() );
		}
	}
#endif
}

long CPGLNodePool::InsertNode(CPGLNodePool::Node pNode)
{
	// PGL_TRACE(_T("NodePool: InsertNode\n"));
	// no null object or already in list
	if (!pNode)
		return 0;

	CSingleLock singleLock(&m_mutex);

	// locking map
	singleLock.Lock();
	if(singleLock.IsLocked())
	{
		// get new id...
		++m_uCurrentID;

		if( m_mNodes.upper_bound(m_uCurrentID) != m_mNodes.end() )
			return 0;

		pNode->SetID(m_uCurrentID);
		// getting iterator
		m_mNodes.insert( 
			m_mNodes.begin(),
			NodeContainer::value_type(m_uCurrentID, pNode) 
			);
		// unlocking
		singleLock.Unlock();
	}

	return m_uCurrentID;
}

void CPGLNodePool::InsertNodeFixedID(CPGLNodePool::Node pNode)
{
	PGL_TRACE(_T("NodePool: InsertNodeFixedID\n"));
	if (!pNode)
		return;

	// first take out of map if in map
	NodeContainer::iterator it=m_mNodes.find(pNode->GetID());
	if( it != m_mNodes.end())
		m_mNodes.erase(it);

	// trying to add at new position
	m_mNodes.insert( 
		NodeContainer::value_type(pNode->GetID(),
		pNode) 
		);
}

bool CPGLNodePool::ChangeID( CPGLNodePool::Node pNode, long uNewID)
{
	if (!pNode)
		return false;

	NodeContainer::iterator it = m_mNodes.find( pNode->GetID() );

	// space if available we can move it...
	if (it != m_mNodes.end())
	{
		m_mNodes.erase(pNode->GetID());

		pNode->SetID(uNewID);
		m_mNodes.insert( NodeContainer::value_type(uNewID,pNode) );

		return true;
	}
	else
		return false;	
}

CPGLNodePool::Node CPGLNodePool::FindNode(long uID)
{
	NodeContainer::iterator it = m_mNodes.find(uID);

	if (it != m_mNodes.end())
		return it->second;
	else
		return CPGLNodeStPtr();
};

bool CPGLNodePool::RemoveNode(long lID)
{
	//PGL_TRACE(_T("NodePool: RemoveNode\n"));
	CSingleLock singleLock(&m_mutex);

	bool bOK=false;
	// locking map
	singleLock.Lock();
	if(singleLock.IsLocked())
	{	
		NodeContainer::iterator it = m_mNodes.find( lID );
		if (it != m_mNodes.end())
		{
			m_mNodes.erase(it);
			bOK=true;
		}

		// updatting
		if (m_mNodes.empty())
			m_uCurrentID=0;

		singleLock.Unlock();
	}

	return bOK;
}

#ifdef _DEBUG
void CPGLNodePool::Dump()
{
	PGL_TRACE1(_T("NodePool:: %d nodes,\n"), m_mNodes.size());

	NodeContainer::iterator it;

	for (it=m_mNodes.begin(); it != m_mNodes.end(); ++it)
	{
		PGL_TRACE1(_T("\tID: %d\n"), it->first);
	}
}

void CPGLNodePoolSingleton::Dump()								
{	
	Instance()->Dump();
}
#endif

size_t CPGLNodePoolSingleton::GetCount()								
{	
	return Instance()->GetCount();
}

size_t CPGLNodePoolSingleton::GetObjectCount()
{	
	return Instance()->GetTypedCount(CPGLObjectStPtr());
}

size_t CPGLNodePoolSingleton::GetDataCount()
{	
	return Instance()->GetTypedCount(CPGLDataStPtr());
}

size_t CPGLNodePoolSingleton::GetBrushCount()
{	
	return Instance()->GetTypedCount(CPGLBrushStPtr());
}

CPGLNodePoolSingleton::Node CPGLNodePoolSingleton::FindNode(long uID)		
{	
	return Instance()->FindNode(uID);
};

template class TPGLPoolSingleton<CPGLBrush>;
template class TPGLPoolSingleton<CPGLData>;
template class TPGLPoolSingleton<CPGLRegion>;
